//19.2.28:更新至v101,JsonLoader已被移除，废掉相应代码
//19.3.18:扩充音频资源加载功能
//19.3.20:GLTF导入增加是否有模型的判断，以避免只导入动画时报错
//19.4.11:增加HDRLoader相关代码的hdr加载功能(.hdr的贴图(texture)或球形映射cubeTexture(renderTarget))
//20.9.23:增加G_Config版本控制相关代码(HDR暂缺)
let THREE=require('three');
import Utils from '../general/utils';
import HDRLoader from './HDR-loader';
import {CubemapGenerator} from './ETC-generator';
import HDRCubeLoader from './HDR-cube-Loader';
import PMREMGenerator from './PMREM-generator';
import PMREMCubeUVPacker from './PMREM-cube-UV-packer';
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader';
import G_Config from 'global-libs/global-setup/g-config';

//资源加载，支持gltf模型（含动画），texture，cubeTexture的加载
export default class Loader extends THREE.EventDispatcher{
    constructor(renderer){
        super();
        this.models={};
        this.textures={};
        this.animations={};
        this.audios={};
        this.targets={};
        this.gltf={};
        this.renderer=renderer;
        this.init();
    }
    get resolution(){
        return 256;
    }
    init(){
        this.initVariable();
        this.initManager();
        this.initLoader();
        this.initEventBind();
        this.loading();
    }
    initVariable(){
        this.url='./';//模型资源路径
        this.urlTexture='./';//贴图资源路径
        this.urlAudio='./';//音频资源路径
        this.loaded={};
        this.items=[];
    }
    initEventBind(){
        this.fireErrorEvent=(error)=>{
            this.dispatchEvent({type:'loadError',paras:{value:error}});
        };
        this.fireProgressEvent=(percent)=>{
            this.dispatchEvent({type:'loadProgress',paras:{value:percent}});
        };
        this.fireLoadedEvent=()=>{
            if((()=>{
                for(let key of Object.keys(this.loaded)){
                    if(this.loaded[key]===false)return true;
                }
                return false;
                })())return;
            this.initModel();
            this.initTexture();
            this.initAnimation();
            this.initAudio();
            this.dispatchEvent({type:'loaded',paras:{
                models:this.models,
                textures:this.textures,
                animations:this.animations,
                gltf:this.gltf,
                audios:this.audios,
                targets:this.targets,
            }});
        };
        this.fireStartEvent=()=>{
            this.dispatchEvent({type:'loadStart',paras:{}});
        };
    }
    initManager(){
        this.manager=new THREE.LoadingManager();
        this.manager.onStart=()=>{
            let msg='开始加载数据!';
            THREE.startLoad(msg);
            this.fireStartEvent();
        };
        this.manager.onError=()=>{
            let msg='数据加载失败!';
            THREE.loadError(msg);
            this.fireErrorEvent();
        };
        this.manager.onLoad=()=>{
            let msg='数据加载完成!';
            THREE.loaded(msg);
        };
        this.manager.onProgress=(url,itemsLoaded,itemsTotal)=>{
            let msg='数据已加载完成:'+(itemsLoaded/itemsTotal*100).toFixed(0)+'%';
            THREE.loading(msg);
            this.fireProgressEvent();
        };
    }
    initLoader(){
        // this.GLTFLoader=new THREE.GLTFLoader(this.manager);
        this.GLTFLoader=new GLTFLoader(this.manager);
        this.textureLoader=new THREE.TextureLoader(this.manager);
        this.cubeTextureLoader=new THREE.CubeTextureLoader(this.manager);
        this.audioLoader=new THREE.AudioLoader(this.manager);
        this.HDRLoader=new HDRLoader(this.manager);
        this.HDRCubeLoader=new HDRCubeLoader(this.manager);
    }
    addItem(url,type,name){
        let tp={};
        tp.url=url;
        tp.type=type;
        tp.name=name;
        this.loaded[''+name+'']=false;
        this.items.push(tp);
    }//添加加载任务
    load(){
        if(this.items.length===0)this.fireLoadedEvent();
        for(let o of this.items){
            this.loadItem(o);
        }
    }//加载所有任务
    loadItem(o){
        switch (o.type){
            case Loader.type.model:
                this.loadModel(o);
                break;
            case Loader.type.texture:
                this.loadTexture(o);
                break;
            case Loader.type.cubeTexture:
                this.loadCubeTexture(o);
                break;
            case Loader.type.audio:
                this.loadAudio(o);
                break;
            case Loader.type.hdr:
                this.loadHDR(o);
                break;
            case Loader.type.hdrSphere:
                this.loadHDRSphere(o);
                break;
            case Loader.type.hdrCube:
                this.loadHDRCube(o);
                break;
        }
    }
    loadTexture(target){
        this.textureLoader.load(G_Config.genUrl(this.urlTexture+target.url),(tex)=>{
            this.textures[''+target.name+'']=tex;
            this.loaded[''+target.name+'']=true;
            this.fireLoadedEvent();
        },onProgress,onError);
    }
    loadCubeTexture(target){
        let urls=[//right,left,top,bottom,front,back
            G_Config.genUrl(this.urlTexture+target.url[0]),G_Config.genUrl(this.urlTexture+target.url[1]),
            G_Config.genUrl(this.urlTexture+target.url[2]),G_Config.genUrl(this.urlTexture+target.url[3]),
            G_Config.genUrl(this.urlTexture+target.url[4]),G_Config.genUrl(this.urlTexture+target.url[5])
        ];
        this.cubeTextureLoader.load(urls,(object)=>{
            this.textures[''+target.name+'']=object;
            this.textures[''+target.name+''].format=THREE.RGBFormat;
            this.textures[''+target.name+''].mapping=THREE.CubeReflectionMapping;
            this.loaded[''+target.name+'']=true;
            this.fireLoadedEvent();
        },onProgress,onError);
    }
    loadModel(target){
        this.GLTFLoader.load(G_Config.genUrl(this.url+target.url),(object)=>{
            this.gltf[''+target.name+'']=Utils.cloneGLTF(object);
            this.animations[''+target.name+'']=object.animations;
            this.models[''+target.name+'']=new THREE.Object3D();
            if(object.scene.children.length>0) {//19.3.20
                this.models['' + target.name + ''].add(...object.scene.children);
            }

            this.loaded[''+target.name+'']=true;
            this.fireLoadedEvent();
        },onProgress,onError);
    }
    loadAudio(target){
        this.audioLoader.load(G_Config.genUrl(this.urlAudio+target.url),(buffer)=>{
            this.audios[''+target.name+'']=buffer;
            this.loaded[''+target.name+'']=true;

            this.fireLoadedEvent();
        },onProgress,onError);
    }
    loadHDR(target){
        this.HDRLoader.load(this.urlTexture+target.url,(tex)=>{
            this.textures[''+target.name+'']=tex;
            this.textures[''+target.name+''].encoding=THREE.RGBEEncoding;
            this.textures[''+target.name+''].minFilter=THREE.NearestFilter;
            this.textures[''+target.name+''].magFilter=THREE.NearestFilter;

            tex.dispose();
            this.loaded[''+target.name+'']=true;
            this.fireLoadedEvent();
        },onProgress,onError);
    }
    loadHDRSphere(target){
        this.HDRLoader.load(this.urlTexture+target.url,(tex)=>{
            tex.encoding=THREE.RGBEEncoding;
            tex.minFilter=THREE.NearestFilter;
            tex.magFilter=THREE.NearestFilter;
            let cubeGenerator = new CubemapGenerator(this.renderer);
            this.targets[''+target.name+'']=cubeGenerator.fromEquirectangular(tex,{resolution:this.resolution});

            tex.dispose();
            this.loaded[''+target.name+'']=true;
            this.fireLoadedEvent();
        },onProgress,onError);
    }
    loadHDRCube(target){
        let urls=[//right,left,top,bottom,front,back
            this.urlTexture+target.url[0],this.urlTexture+target.url[1],
            this.urlTexture+target.url[2],this.urlTexture+target.url[3],
            this.urlTexture+target.url[4],this.urlTexture+target.url[5]
        ];
        this.HDRCubeLoader.load(THREE.UnsignedByteType,urls,(tex)=>{
            let pmremGenerator=new PMREMGenerator(tex,32,this.resolution);
            pmremGenerator.update(this.renderer);
            let pmremCubeUVPacker=new PMREMCubeUVPacker(pmremGenerator.cubeLods);
            pmremCubeUVPacker.update(this.renderer);
            let hdrCubeRenderTarget=pmremCubeUVPacker.CubeUVRenderTarget;

            tex.dispose();
            pmremGenerator.dispose();
            pmremCubeUVPacker.dispose();
            this.targets[''+target.name+'']=hdrCubeRenderTarget;

            this.loaded[''+target.name+'']=true;
            this.fireLoadedEvent();
        },onProgress,onError);
    }
    loading(){
        this.load();
    }//加载
    initModel(){}//初始化模型
    initTexture(){}//初始化贴图
    initAnimation(){}//初始化动画
    initAudio(){}//初始化音频
}

let onProgress=(xhr={lengthComputable:false})=>{
    if ( xhr.lengthComputable ) {
        let percentComplete = xhr.loaded / xhr.total * 100;
        console.log(Utils.normalizeNumber(percentComplete,0.01) + '% downloaded' );
    }
};
let onError=(xhr)=>{
    console.error('error??',xhr);
};

Loader.type={
    texture:'texture',
    model:'model',
    cubeTexture:'cubeTexture',
    audio:'audio',
    hdr:'hdr',
    hdrSphere:'hdrSphere',
    hdrCube:'hdrCube',//
};